using System.IO;


namespace Ultima {
  public class FileIndex {
    private readonly Entry3D[] m_Index;
    private readonly Stream m_Stream;

    public FileIndex( string idxFile, string mulFile, int length, int file ) {
      this.m_Index = new Entry3D[length];

      string idxPath = Client.GetFilePath( idxFile );
      string mulPath = Client.GetFilePath( mulFile );

      if ( idxPath != null && mulPath != null ) {
        using ( var index = new FileStream( idxPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) {
          var bin = new BinaryReader( index );
          this.m_Stream = new FileStream( mulPath, FileMode.Open, FileAccess.Read, FileShare.Read );

          var count = (int)( index.Length / 12 );

          for ( int i = 0; i < count && i < length; ++i ) {
            this.m_Index[i].lookup = bin.ReadInt32();
            this.m_Index[i].length = bin.ReadInt32();
            this.m_Index[i].extra = bin.ReadInt32();
          }

          for ( int i = count; i < length; ++i ) {
            this.m_Index[i].lookup = -1;
            this.m_Index[i].length = -1;
            this.m_Index[i].extra = -1;
          }
        }
      }

      Entry5D[] patches = Verdata.Patches;

      for ( int i = 0; i < patches.Length; ++i ) {
        Entry5D patch = patches[i];

        if ( patch.file == file && patch.index >= 0 && patch.index < length ) {
          this.m_Index[patch.index].lookup = patch.lookup;
          this.m_Index[patch.index].length = patch.length | ( 1 << 31 );
          this.m_Index[patch.index].extra = patch.extra;
        }
      }
    }

    public Entry3D[] Index {
      get { return this.m_Index; }
    }
    public Stream Stream {
      get { return this.m_Stream; }
    }

    public Stream Seek( int index, out int length, out int extra, out bool patched ) {
      if ( index < 0 || index >= this.m_Index.Length ) {
        length = extra = 0;
        patched = false;
        return null;
      }

      Entry3D e = this.m_Index[index];

      if ( e.lookup < 0 ) {
        length = extra = 0;
        patched = false;
        return null;
      }

      length = e.length & 0x7FFFFFFF;
      extra = e.extra;

      if ( ( e.length & ( 1 << 31 ) ) != 0 ) {
        patched = true;

        Verdata.Stream.Seek( e.lookup, SeekOrigin.Begin );
        return Verdata.Stream;
      } else if ( this.m_Stream == null ) {
        length = extra = 0;
        patched = false;
        return null;
      }

      patched = false;

      this.m_Stream.Seek( e.lookup, SeekOrigin.Begin );
      return this.m_Stream;
    }
  }


  public struct Entry3D {
    public int extra;
    public int length;
    public int lookup;
  }
}